﻿using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using CthulhuDomain;
using CthulhuDomain.GameEntities;
using CthulhuDomain.Services;
using CthulhuDomain.StageManagement;
using Microsoft.Pex.Framework;
using Microsoft.Pex.Framework.Validation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
using Microsoft.Xna.Framework.Input;

namespace Invaders.Test.Factories.GameEntities
{
  [TestClass]
  public partial class CollisionManagerFixture
  {
    #region setup

    private static ContentManager contentManager;
    private SpriteBatchAdapter spriteBatch;
    private GameServiceManager gameServiceManager;
    private RectangleAdapter _rectangleAdapter;
    private GameTime _gameTime;

    [TestInitialize]
    public void TestInitialize()
    {
      var gd = new MockedGraphicsDeviceService(DeviceType.Hardware, GraphicsProfile.HiDef);
      gd.CreateDevice();

      string activeConfinguration;
#if DEBUG
      activeConfinguration = "Debug";
#else
      activeConfinguration = "Release";

#endif
      spriteBatch = new SpriteBatchAdapter(gd.GraphicsDevice);
      contentManager = new ContentManager(gd.ServiceProvider)
                         {
                           RootDirectory =
                             Path.GetFullPath(string.Format("../../../CthulhuInvaders/bin/x86/{0}/Content/",
                                                            activeConfinguration))
                         };

      gameServiceManager = new GameServiceManager(new GameAdapter(new Game()), new ContentManagerAdapter(contentManager),
                                                  spriteBatch, new RectangleAdapter(0, 0, 300, 300));
    }

    [TestCleanup]
    public void MyTestCleanup()
    {
      contentManager = null;
      spriteBatch = null;
      gameServiceManager = null;
    }

    private static ContentManagerAdapter InitMatrix(out DomainEntityMatrix matrix, out DomainEntity player)
    {
      var CM = new ContentManagerAdapter(contentManager);
      var RA = new RectangleAdapter(0, 0, 300, 300);
      player = DomainFactory.GetFactory(DomainFactory.eTypeEntity.Player).CreateEntity(CM,
                                                                                       new PlayerState()
                                                                                         {
                                                                                           LifePoints = 3,
                                                                                           StartingPosition =
                                                                                             new Vector2Adapter(100, 300)
                                                                                         });
      var matrixConfigurations = CM.LoadSetUp();
      var level = matrixConfigurations.SingleOrDefault(x => x.ID == 1);
      matrix = new DomainEntityMatrix(level.Schema);
      matrix.LoadContent(CM, RA);
      return CM;
    }

    #endregion

    [PexMethod]
    public void CheckPlayerCollision_EntityVsPlayerFullLife_PlayerLifeDecreaseByOne()
    {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;
      var CM = InitMatrix(out matrix, out player);
      player = DomainFactory.GetFactory(DomainFactory.eTypeEntity.Player).CreateEntity(CM,new PlayerState(){LifePoints = 3, StartingPosition = new Vector2Adapter(100,300)});
      player.Position = matrix.GetElement(2, 2).Position;
      var result = new ScoreManager.CollisionResult();
      // Act
      var oldLifePoint = player.LifePoint;
      result = CollisionManager.DetectCollision(matrix, player);
      // Assert
      Assert.IsTrue(player.LifePoint < oldLifePoint);
      Trace.WriteLine(string.Format("Old player life points :{0}, New player life points: {1}", oldLifePoint, player.LifePoint));
    }

    [PexMethod]
    public void CheckPlayerCollision_EntityPowerUpVSPlayer_PlayerGetPowerUp()
    {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;
      var CM = InitMatrix(out matrix, out player);
      CollisionManager.Initialize(gameServiceManager, (LevelStage)StageFactory.GetFactory(StageFactory.eTypeStage.Level, gameServiceManager).CreateEntity());

      var entity = matrix.GetElement(2,2);
      var powerUp = PowerUpFactory.GetFactory(PowerUpFactory.ePowerUp.Life).CreatePowerUp(CM);
      entity.AddPowerUp(powerUp);
      CollisionManager.GetPowerUp(0).Position = player.Position;
      matrix.SetElement(2,2,entity);
      var oldLP = player.LifePoint;

      // Act
      var result = CollisionManager.DetectCollision(matrix, player);
      result.Modifier.Execute(ref player,ref matrix);
      // Assert
      Assert.IsTrue(player.LifePoint > oldLP);
      Trace.WriteLine(string.Format("Old player life points :{0}, New player life points: {1}", oldLP, player.LifePoint));
    }

    [PexMethod]
    public void CheckPlayerCollision_EntityPowerUpVsPlayer_MessageAreTriggered()
    {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;
      var CM = InitMatrix(out matrix, out player);
      Cthulhu entity = (Cthulhu)matrix.GetElement(2, 2);
      CollisionManager.Initialize(gameServiceManager, (LevelStage)StageFactory.GetFactory(StageFactory.eTypeStage.Level, gameServiceManager).CreateEntity());

      var powerUp = PowerUpFactory.GetFactory(PowerUpFactory.ePowerUp.Life).CreatePowerUp(CM);
      entity.AddPowerUp(powerUp);
      CollisionManager.GetPowerUp(0).Position = player.Position;
      matrix.SetElement(2, 2, entity);
      var oldLP = player.LifePoint;
      // Act
      var result = CollisionManager.DetectCollision(matrix, player);
      result.Modifier.Execute(ref player, ref matrix);

      
      // Assert
      Assert.IsTrue(player.LifePoint > oldLP);
      Trace.WriteLine(string.Format("Old player life points :{0}, New player life points: {1}", oldLP, player.LifePoint));
    }

    [PexMethod]
    public void CheckPlayerCollision_EntityBangVsPlayer_PlayerLifePointsDecrease() {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;

      var CM = InitMatrix(out matrix, out player);
      var entity = matrix.GetElement(2, 2);
      var oldLP = player.LifePoint;
      CollisionManager.Initialize(gameServiceManager, (LevelStage)StageFactory.GetFactory(StageFactory.eTypeStage.Level, gameServiceManager).CreateEntity());
      entity.AddShoot();
      _rectangleAdapter = new RectangleAdapter(0, 0, 300, 300);
      _gameTime = new GameTime(new TimeSpan(0, 0, 0, 1), new TimeSpan(0, 0, 0, 2));
      CollisionManager.GetShoot(0).Position = new Vector2Adapter(150, 150);
      player.Position = CollisionManager.GetShoot(0).Position;
      // Act
      var result = CollisionManager.DetectCollision(matrix, player);
      // Assert
      Assert.IsTrue(player.LifePoint < oldLP);
      Trace.WriteLine(string.Format("Old player life points :{0}, New player life points: {1}", oldLP, player.LifePoint));
    }

    [PexMethod]
    public void CheckPlayerCollision_AllEntityArmyIsNull_StageComplete()
    {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;
      var CM = new ContentManagerAdapter(contentManager);
      var RA = new RectangleAdapter(0, 0, 300, 300);
      player = DomainFactory.GetFactory(DomainFactory.eTypeEntity.Player).CreateEntity(CM,
                                                                                       new PlayerState() {
                                                                                         LifePoints = 3,
                                                                                         StartingPosition =
                                                                                           new Vector2Adapter(100, 300)
                                                                                       });
      var matrixConfigurations = CM.LoadSetUp();
      var level = matrixConfigurations.SingleOrDefault(x => x.ID == 1);
      matrix = new DomainEntityMatrix(level.Schema);
      CollisionManager.Initialize(gameServiceManager, (LevelStage)StageFactory.GetFactory(StageFactory.eTypeStage.Level, gameServiceManager).CreateEntity());
      var xl = matrix.XLength -1 ;
      var yl = matrix.YLength -1;
      
      // Act
      var result = CollisionManager.DetectCollision(matrix, player);
      // Assert
      Assert.AreEqual(ScoreManager.CollisionResult.eResultType.StageComplete, result.ResultType);
    }
    
    [PexMethod]
    public void CheckPlayerCollision_PlayerLifePoint0_PlayerDie()
    {
      // Arrange
      DomainEntityMatrix matrix;
      DomainEntity player;
      var CM = InitMatrix(out matrix, out player);
      CollisionManager.Initialize(gameServiceManager, (LevelStage)StageFactory.GetFactory(StageFactory.eTypeStage.Level, gameServiceManager).CreateEntity());
      player.Position = matrix.GetElement(2,2).Position;
      
      // Act
      var result = CollisionManager.DetectCollision(matrix, player);
      // Assert
      Assert.AreEqual(ScoreManager.CollisionResult.eResultType.PlayerDie, result.ResultType);
    }
  }
}
